package site.isscloud.quartz.task;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import site.isscloud.common.utils.StringUtils;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 告警模拟HTTP调用任务（带轮次调度机制）
 */
@Component("alarmHttpTask")
public class AlarmHttpTask {

    private static final Logger log = LoggerFactory.getLogger(AlarmHttpTask.class);
    private static final Logger simulateLog = LoggerFactory.getLogger("simulate");

    @Autowired
    private RestTemplate restTemplate;

    @Value("${server.port:8080}")
    private String serverPort;

    // 改为非静态字段，通过方法获取
    private String getBaseUrl() {
        return "http://localhost:" + serverPort + "/project/alarm/simulate";
    }

    private Random random = new Random();

    // 模拟设备配置
    private static final String DEVICE_NO = "001";
    private static final Integer CHANNEL = 1;
    private static final int MIN_METER_MARK = 101;
    private static final int MAX_METER_MARK = 1500;

    // 轮次配置
    private static final int TOTAL_ROUNDS = 5; // 总轮次数
    private static final Map<Integer, RoundConfig> ROUND_CONFIGS = new HashMap<>();

    static {
        // 断纤告警轮：2次一轮，权重20%
        ROUND_CONFIGS.put(1, new RoundConfig(1, "断纤告警轮", 2, 0.2));
        // 激光器故障轮：2次一轮，权重20%
        ROUND_CONFIGS.put(2, new RoundConfig(2, "激光器故障轮", 2, 0.2));
        // 温度告警轮：6次一轮，权重60%
        ROUND_CONFIGS.put(3, new RoundConfig(3, "温度告警轮", 6, 0.6));
    }

    // 轮次执行状态
    private static RoundExecutionState executionState = new RoundExecutionState();

    /**
     * 模拟告警数据发送任务
     */
    public void sendAlarmData() {
        try {
            simulateLog.info("=== 开始发送模拟告警数据 ===");

            // 1. 确定当前轮次
            int currentRoundType = determineCurrentRound();
            RoundConfig currentConfig = ROUND_CONFIGS.get(currentRoundType);

            simulateLog.info("当前轮次: {}, 剩余执行次数: {}/{}",
                    currentConfig.name,
                    executionState.currentRoundRemainingCount,
                    currentConfig.roundCount);

            // 2. 执行当前轮次的告警
            executeRoundAlarm(currentRoundType);

            // 3. 更新轮次状态
            updateRoundState(currentConfig);

            simulateLog.info("=== 模拟告警数据发送完成 ===");

        } catch (Exception e) {
            log.error("发送模拟告警数据失败", e);
            simulateLog.error("发送模拟告警数据失败: {}", e.getMessage());
        }
    }

    /**
     * 确定当前轮次
     */
    private int determineCurrentRound() {
        // 如果当前有正在执行的轮次，继续执行
        if (executionState.currentRoundType != 0 && executionState.currentRoundRemainingCount > 0) {
            return executionState.currentRoundType;
        }

        // 开始新的轮次
        return selectNewRound();
    }

    /**
     * 选择新的轮次
     */
    private int selectNewRound() {
        // 检查各轮次是否已达到最大次数限制
        Map<Integer, Double> availableWeights = new HashMap<>();
        double totalWeight = 0.0;

        for (RoundConfig config : ROUND_CONFIGS.values()) {
            int maxRounds = (int) (config.weight * TOTAL_ROUNDS);
            if (executionState.roundExecutedCount.getOrDefault(config.type, 0) < maxRounds) {
                availableWeights.put(config.type, config.weight);
                totalWeight += config.weight;
            }
        }

        // 如果没有可用的轮次，重置计数
        if (availableWeights.isEmpty()) {
            simulateLog.info("所有轮次都已完成最大次数，重置计数");
            executionState.roundExecutedCount.clear();
            return selectNewRound(); // 递归调用
        }

        // 根据权重随机选择轮次
        double randomValue = random.nextDouble() * totalWeight;
        double currentWeight = 0.0;

        for (Map.Entry<Integer, Double> entry : availableWeights.entrySet()) {
            currentWeight += entry.getValue();
            if (randomValue <= currentWeight) {
                int selectedRound = entry.getKey();
                RoundConfig config = ROUND_CONFIGS.get(selectedRound);

                // 初始化新轮次
                executionState.currentRoundType = selectedRound;
                executionState.currentRoundRemainingCount = config.roundCount;

                simulateLog.info("选择新轮次: {}, 权重: {}, 执行次数: {}",
                        config.name, config.weight, config.roundCount);

                return selectedRound;
            }
        }

        // 默认返回第一个可用的轮次
        return availableWeights.keySet().iterator().next();
    }

    /**
     * 执行轮次告警
     */
    private void executeRoundAlarm(int roundType) {
        switch (roundType) {
            case 1:
                executeFiberAlarmRound();
                break;
            case 2:
                executeLaserAlarmRound();
                break;
            case 3:
                executeTemperatureAlarmRound();
                break;
        }
    }

    /**
     * 执行断纤告警轮
     */
    private void executeFiberAlarmRound() {
        int fiberPosition = MIN_METER_MARK + random.nextInt(MAX_METER_MARK - MIN_METER_MARK);

        Map<String, Object> alarmData = new HashMap<>();
        alarmData.put("deviceNo", DEVICE_NO);
        alarmData.put("chanel", CHANNEL);
        alarmData.put("alarmType", 1); // 断纤告警
        alarmData.put("fiberBreakPosition", fiberPosition);
        alarmData.put("sData", String.format("{\"type\":\"fiber_break\",\"position\":%d,\"device\":\"%s\",\"channel\":%d}",
                fiberPosition, DEVICE_NO, CHANNEL));

        sendHttpRequest(alarmData);
        simulateLog.info("执行断纤告警轮 - 位置: {}", fiberPosition);
    }

    /**
     * 执行激光器故障告警轮
     */
    private void executeLaserAlarmRound() {
        int laserTemp = 75 + random.nextInt(20); // 75-95度

        Map<String, Object> alarmData = new HashMap<>();
        alarmData.put("deviceNo", DEVICE_NO);
        alarmData.put("chanel", CHANNEL);
        alarmData.put("alarmType", 2); // 激光器故障
        alarmData.put("laserTemperature", laserTemp);
        alarmData.put("sData", String.format("{\"type\":\"laser_fault\",\"temperature\":%d,\"device\":\"%s\",\"channel\":%d}",
                laserTemp, DEVICE_NO, CHANNEL));

        sendHttpRequest(alarmData);
        simulateLog.info("执行激光器故障告警轮 - 温度: {}°C", laserTemp);
    }

    /**
     * 执行温度告警轮
     */
    private void executeTemperatureAlarmRound() {
        // 获取或创建温度告警段
        TempAlarmSegment segment = getOrCreateTempSegment();

        // 发送该段内所有米标的温度告警
        for (int i = 0; i < segment.meterMarks.length; i++) {
            int meterMark = segment.meterMarks[i];
            BigDecimal temperature = segment.temperatures[i];

            Map<String, Object> alarmData = new HashMap<>();
            alarmData.put("deviceNo", DEVICE_NO);
            alarmData.put("chanel", CHANNEL);
            alarmData.put("alarmType", 3); // 温度告警
            alarmData.put("meterMark", meterMark);
            alarmData.put("meterAlarmTemperature", temperature);
            alarmData.put("meterAlarmStatus", 1);
            alarmData.put("sData", String.format("{\"type\":\"temperature\",\"meter_mark\":%d,\"temperature\":%.1f,\"device\":\"%s\",\"channel\":%d}",
                    meterMark, temperature, DEVICE_NO, CHANNEL));

            sendHttpRequest(alarmData);
        }

        // 更新温度（持续升温）
        segment.increaseTemperatures();
        saveTempSegment(segment);

        simulateLog.info("执行温度告警轮 - 米标段: {}-{}, 温度: {}-{}°C, 升温次数: {}",
                segment.startMark, segment.endMark,
                segment.getMinTemperature(), segment.getMaxTemperature(),
                segment.increaseCount);
    }

    /**
     * 更新轮次状态
     */
    private void updateRoundState(RoundConfig config) {
        executionState.currentRoundRemainingCount--;

        // 如果当前轮次执行完毕
        if (executionState.currentRoundRemainingCount <= 0) {
            // 增加该轮次的执行计数
            int executedCount = executionState.roundExecutedCount.getOrDefault(config.type, 0);
            executionState.roundExecutedCount.put(config.type, executedCount + 1);

            // 重置当前轮次
            executionState.currentRoundType = 0;
            executionState.currentRoundRemainingCount = 0;

            simulateLog.info("轮次执行完成: {}, 总执行次数: {}",
                    config.name, executionState.roundExecutedCount.get(config.type));
        }
    }

    /**
     * 发送HTTP请求
     */
    private void sendHttpRequest(Map<String, Object> alarmData) {
        try {
            // 使用getBaseUrl()方法获取URL
            String url = getBaseUrl() + "/receive";

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            HttpEntity<Map<String, Object>> request = new HttpEntity<>(alarmData, headers);

            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);

            if (response.getStatusCode().is2xxSuccessful()) {
                simulateLog.debug("HTTP请求成功: {}", response.getBody());
            } else {
                simulateLog.error("HTTP请求失败: {}", response.getStatusCode());
            }

        } catch (Exception e) {
            simulateLog.error("HTTP请求异常: {}", e.getMessage());
        }
    }

    /**
     * 获取或创建温度告警段
     */
    private TempAlarmSegment getOrCreateTempSegment() {
        TempAlarmSegment segment = (TempAlarmSegment) executionState.tempAlarmState.get("currentSegment");
        if (segment == null) {
            segment = createNewTempSegment();
        }
        return segment;
    }

    /**
     * 创建新的温度告警段
     */
    private TempAlarmSegment createNewTempSegment() {
        int segmentLength = 5 + random.nextInt(6); // 5-10个米标
        int startMark = MIN_METER_MARK + random.nextInt(MAX_METER_MARK - MIN_METER_MARK - segmentLength);

        TempAlarmSegment segment = new TempAlarmSegment(startMark, segmentLength);
        saveTempSegment(segment);

        simulateLog.info("创建新的温度告警段: {}-{}, 长度: {}",
                segment.startMark, segment.endMark, segmentLength);

        return segment;
    }

    /**
     * 保存温度告警段
     */
    private void saveTempSegment(TempAlarmSegment segment) {
        executionState.tempAlarmState.put("currentSegment", segment);
    }

    /**
     * 轮次配置类
     */
    private static class RoundConfig {
        int type;           // 轮次类型：1-断纤，2-激光器，3-温度
        String name;        // 轮次名称
        int roundCount;     // 每轮执行次数
        double weight;      // 权重

        public RoundConfig(int type, String name, int roundCount, double weight) {
            this.type = type;
            this.name = name;
            this.roundCount = roundCount;
            this.weight = weight;
        }
    }

    /**
     * 轮次执行状态类
     */
    private static class RoundExecutionState {
        int currentRoundType = 0;                   // 当前轮次类型
        int currentRoundRemainingCount = 0;         // 当前轮次剩余执行次数
        Map<Integer, Integer> roundExecutedCount = new HashMap<>(); // 各轮次已执行次数
        Map<String, Object> tempAlarmState = new HashMap<>();       // 温度告警状态
    }

    /**
     * 温度告警段内部类
     */
    private static class TempAlarmSegment {
        int startMark;
        int endMark;
        int[] meterMarks;
        BigDecimal[] temperatures;
        int increaseCount;

        public TempAlarmSegment(int startMark, int length) {
            this.startMark = startMark;
            this.endMark = startMark + length - 1;
            this.meterMarks = new int[length];
            this.temperatures = new BigDecimal[length];
            this.increaseCount = 0;

            // 初始化米标和温度
            Random localRandom = new Random();
            double baseTemp = 35.0 + localRandom.nextDouble() * 10.0; // 35-45度基础温度

            for (int i = 0; i < length; i++) {
                meterMarks[i] = startMark + i;
                // 中间温度高，两边温度低
                double distance = Math.abs(i - (length / 2.0)) / (length / 2.0);
                double temp = baseTemp + (1.0 - distance) * 5.0; // 中心比边缘高5度
                temperatures[i] = BigDecimal.valueOf(temp).setScale(1, BigDecimal.ROUND_HALF_UP);
            }
        }

        /**
         * 增加温度（持续升温）
         */
        public void increaseTemperatures() {

            increaseCount++;
            for (int i = 0; i < temperatures.length; i++) {
                double newTemp = temperatures[i].doubleValue() + 0.5; // 每次升高0.5度
                temperatures[i] = BigDecimal.valueOf(newTemp).setScale(1, BigDecimal.ROUND_HALF_UP);
            }
            Random localRandom = new Random();
            // 升温10次后重置
            if (increaseCount >= 10) {
                increaseCount = 0;
                // 创建新的温度段
                TempAlarmSegment newSegment = new TempAlarmSegment(
                        MIN_METER_MARK + localRandom.nextInt(MAX_METER_MARK - MIN_METER_MARK - 10),
                        5 + localRandom.nextInt(6));
                this.startMark = newSegment.startMark;
                this.endMark = newSegment.endMark;
                this.meterMarks = newSegment.meterMarks;
                this.temperatures = newSegment.temperatures;
            }
        }

        public double getMinTemperature() {
            double min = Double.MAX_VALUE;
            for (BigDecimal temp : temperatures) {
                if (temp.doubleValue() < min) {
                    min = temp.doubleValue();
                }
            }
            return min;
        }

        public double getMaxTemperature() {
            double max = Double.MIN_VALUE;
            for (BigDecimal temp : temperatures) {
                if (temp.doubleValue() > max) {
                    max = temp.doubleValue();
                }
            }
            return max;
        }
    }
}